package org.spring.bean.factory.config;

import com.sun.istack.internal.Nullable;
import org.spring.bean.exceptions.BeansException;
import org.spring.core.Ordered;

/**
 * 允许自定义修改新 bean 实例的工厂挂钩 - 例如，检查标记接口或使用代理包装 bean。
 *
 * <p>通常，通过标记接口等填充 bean 的后处理器将实现 {@link #postProcessBeforeInitialization}，
 * 而使用代理包装 bean 的后处理器通常会实现 {@link #postProcessAfterInitialization}。
 *
 * <h3>Registration</h3>
 * <p>
 * {@code ApplicationContext}可以在其bean定义中自动检测{@code BeanPostProcessor} bean，并将这些后处理程序应用于随后创建的任何bean。
 * 普通的{@code BeanFactory}允许对后处理器进行编程注册，将它们应用于通过bean工厂创建的所有bean。
 *
 * <h3>Ordering</h3>
 * <p>
 * 在{@code ApplicationContext}中自动检测到的bean将根据{@link prioritorderdered}和{@link Ordered}语义。
 * 相反，用{@code BeanPostProcessor}编程方式注册的{@code BeanFactory} bean将按照注册的顺序应用；
 * 任何通过实现{@code PriorityOrdered}或{@code Ordered}接口表达的排序语义将被编程注册的后处理程序忽略。
 * 此外，{@code BeanPostProcessor} bean没有考虑到{@link org.springframework.core.annotation.Order @Order}注释。
 *
 * @author 李坤
 * @date 2022/4/23 19:23
 */
public interface BeanPostProcessor {

    /**
     * 将此 {@code BeanPostProcessor} 应用于给定的新 bean 实例 <i>before<i> 任何 bean 初始化回调
     * （如 InitializingBean 的 {@code afterPropertiesSet} 或自定义 init 方法）。
     * bean 将已填充属性值。返回的 bean 实例可能是原始的包装器。
     *
     * <p>默认实现按原样返回给定的 {@code bean}。
     *
     * @param bean     新的 bean 实例
     * @param beanName bean 的名称
     *
     * @return 要使用的bean实例，无论是原始的还是封装的；如果{@code null}，则不会调用后续的BeanPostProcessors函数
     *
     * @throws org.springframework.beans.BeansException 以防出现错误
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
     */
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    /**
     * 在<i>任何bean初始化回调之后(如InitializingBean的{@code afterPropertiesSet}或自定义初始化方法)将这个{@code
     * BeanPostProcessor}应用到给定的新bean实例<i>。
     * bean已经填充了属性值。返回的bean实例可能是原始bean的包装器。
     * <p>
     * 对于FactoryBean，这个回调将为FactoryBean实例和由FactoryBean创建的对象(从Spring 2.0开始)调用。
     * 后处理器可以决定是应用到FactoryBean还是已创建的对象，或者通过相应的{@code bean instanceof FactoryBean}检查两者。
     * <p>
     * 与所有其他的{@code BeanPostProcessor}回调相比，这个回调也会在由{@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}方法触发的短路之后被调用。
     * <p>
     * 默认实现返回给定的{@code bean}原样。
     *
     * @param bean     新的 bean 实例
     * @param beanName bean 的名称
     *
     * @return 要使用的bean实例，无论是原始的还是封装的；如果{@code null}，则不会调用后续的BeanPostProcessors函数
     *
     * @throws org.springframework.beans.BeansException 以防出现错误
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
     * @see org.springframework.beans.factory.FactoryBean
     */
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}
